package vip.zhenzicheng.test.juc.lock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.StampedLock;

/**
 * @author zhenzicheng
 * @date 2022-09-21 14:21
 */
public class StampedLockCase {

  static int number;
  static StampedLock stampedLock = new StampedLock();

  public void write() {
    // 加锁返回戳记
    long stamp = stampedLock.writeLock();
    System.out.println(Thread.currentThread().getName() + "\t写线程准备修改");
    try {
      number++;
    } finally {
      stampedLock.unlockWrite(stamp);
    }
    System.out.println(Thread.currentThread().getName() + "\t写线程修改完毕");
  }

  public void read() {
    long stamp = stampedLock.readLock();
    System.out.println(Thread.currentThread().getName() + "\t 读锁进入，暂停4s");
    for (int i = 0; i < 4; i++) {
      try {
        TimeUnit.SECONDS.sleep(1);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println(Thread.currentThread().getName() + "\t正在读取中");
    }
    try {
      int result = number;
      System.out.println(Thread.currentThread().getName() + "\t获取成员变量值 result: " + result);
    } finally {
      stampedLock.unlockRead(stamp);
    }
  }

  public void tryOptimisticRead() {
    long stamp = stampedLock.tryOptimisticRead();
    int result = number;

    // 故意间隔4s，乐观认为读取中没有其它线程修改过number值
    System.out.println("4s前戳记校验结果: " + stampedLock.validate(stamp));
    for (int i = 0; i < 4; i++) {
      try {
        TimeUnit.SECONDS.sleep(1);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println(Thread.currentThread().getName() + "\t正在读取..." + i + "s 当前戳记校验结果: " +
        stampedLock.validate(stamp));
    }
    if (!stampedLock.validate(stamp)) {
      System.out.println("有人修改过----有写操作");
      try {
        // 变更为悲观读
        stamp = stampedLock.readLock();
        System.out.println("从乐观读锁升级为悲观读");
        result = number;
        System.out.println("重新悲观读后 result: " + result);
      } finally {
        stampedLock.unlockRead(stamp);
      }
    }
    System.out.println(Thread.currentThread().getName() + " finally value: " + result);
  }

  public static void main(String[] args) {
    StampedLockCase resource = new StampedLockCase();
    // 传统版
    //   new Thread(() -> {
    //     resource.read();
    //   }, "readThread").start();
    //   try {
    //     TimeUnit.SECONDS.sleep(1);
    //   } catch (InterruptedException e) {
    //     e.printStackTrace();
    //   }
    //   new Thread(() -> {
    //     System.out.println(Thread.currentThread().getName() + "\t ----come in");
    //     resource.write();
    //   }, "writeThread").start();

    // 新版
    new Thread(() -> {
      resource.tryOptimisticRead();
    }, "readThread").start();
    try {
      TimeUnit.SECONDS.sleep(3);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    new Thread(() -> {
      System.out.println(Thread.currentThread().getName() + "\t----come in");
      resource.write();
    }, "writeThread").start();

  }
}
